#include "EventLoop.hpp"

int EventLoop::addEvent(int socketfd, unsigned int events, CallBackPtr callback){
    if (socketCallBack_.find(socketfd) != socketCallBack_.end()) {
        return modEvent(socketfd, events, callback);
    }
    epoll_event event;
    event.data.fd = socketfd;
    event.events = events;
    int res = epoll_ctl(epfd_, EPOLL_CTL_ADD, socketfd, &event);
    if (res == -1) {
        perror("addEvent");
        return -1;
    }
    socketCallBack_[socketfd] = callback;
    ConnectionPtr connPtr = std::make_shared<TcpConnection>(socketfd, this);
    connections_[socketfd] = connPtr;
    return res;
}


int EventLoop::delEvent(int socketfd) {
    if (socketCallBack_.find(socketfd) == socketCallBack_.end()) {
        return 0;
    }
    int res = epoll_ctl(epfd_, EPOLL_CTL_DEL, socketfd, nullptr);
    if (res == -1) {
        perror("delEvent");
        return -1;
    }
    socketCallBack_.erase(socketfd);
    connections_.erase(socketfd);
    return res;
}

int EventLoop::modEvent(int socketfd, unsigned int events, CallBackPtr callback) {
    if (socketCallBack_.find(socketfd) == socketCallBack_.end()) {
        return -1;
    }
    epoll_event event;
    event.data.fd = socketfd;
    event.events = events;
    int res = epoll_ctl(epfd_, EPOLL_CTL_MOD, socketfd, &event);
    if (res == -1) {
        perror("modEvent");
        return -1;
    }
    socketCallBack_.erase(socketfd);
    socketCallBack_[socketfd] = callback;
    return res;
}

int EventLoop::addNormalEvent(int socketfd, unsigned int events, NormalCallBack callback){
    if (normalCallBack_.find(socketfd) != normalCallBack_.end()) {
        return modNormalEvent(socketfd, events, callback);
    }
    epoll_event event;
    event.data.fd = socketfd;
    event.events = events;
    int res = epoll_ctl(epfd_, EPOLL_CTL_ADD, socketfd, &event);
    if (res == -1) {
        perror("addEvent");
        return -1;
    }
    normalCallBack_[socketfd] = callback;
    return res;

}

int EventLoop::delNormalEvent(int socketfd){
    if (normalCallBack_.find(socketfd) == normalCallBack_.end()) {
        return 0;
    }
    int res = epoll_ctl(epfd_, EPOLL_CTL_DEL, socketfd, nullptr);
    if (res == -1) {
        perror("delEvent");
        return -1;
    }
    normalCallBack_.erase(socketfd);
    return res;

}

int EventLoop::modNormalEvent(int socketfd, unsigned int events, NormalCallBack callback){
    if (normalCallBack_.find(socketfd) == normalCallBack_.end()) {
        return -1;
    }
    epoll_event event;
    event.data.fd = socketfd;
    event.events = events;
    int res = epoll_ctl(epfd_, EPOLL_CTL_MOD, socketfd, &event);
    if (res == -1) {
        perror("modEvent");
        return -1;
    }
    normalCallBack_.erase(socketfd);
    normalCallBack_[socketfd] = callback;
    return res;
}


void EventLoop::run() {
    if (socketCallBack_.size() + normalCallBack_.size() == 0) {
        std::cerr << "no event in event loop." << std::endl;
        return ;
    }
    int epct=0;
    epoll_event* temp;
    while (true) {
        epct = epoll_wait(epfd_, event_array_, EVENT_ARRAY_LEN, -1);
        for (int i=0; i<epct; ++i) {
            temp = event_array_ + i;
            // if (temp -> events & EPOLLOUT) {
            //     // std::cout << "EPOLLOUT" << std::endl;
            //     connections_[temp->data.fd]->writeSocket();
            // }
            if ((temp -> events & EPOLLIN) && socketCallBack_.find(temp->data.fd) != socketCallBack_.end() && socketCallBack_[temp -> data.fd] != nullptr){
                (*socketCallBack_[temp -> data.fd])(connections_[temp -> data.fd]);
            }
            else if ((temp -> events & EPOLLIN) && normalCallBack_.find(temp->data.fd) != normalCallBack_.end() && normalCallBack_[temp -> data.fd] != nullptr){
                (*normalCallBack_[temp -> data.fd])();
            }
        }
    }
}